function text = maptext2(img, settings)
%MAPTEXT2(IMG, SETTINGS)
% Get text from images with dots.

if ~isfield(settings, 'dpi')
    settings.dpi = 600;
end
if ~isfield(settings, 'blocksize')
    settings.blocksize = 18;
end
if ~isfield(settings, 'bigblocknumx')
    settings.bigblocknumx = 3;
end
if ~isfield(settings, 'bigblocknumy')
    settings.bigblocknumy = 3;
end
if ~isfield(settings, 'seed')
    settings.seed = 0;
end
if ~isfield(settings, 'skipwhite')
    settings.skipwhite = 1;
end
if ~isfield(settings, 'q')
    settings.q = 5;
end
if ~isfield(settings, 'samecolor')
    settings.samecolor = 5;
end
if ~isfield(settings, 'maxiteration')
    settings.maxiteration = 20;
end
if ~isfield(settings, 'mutualinfo')
    settings.mutualinfo = 0.99;
end
if ~isfield(settings, 'msgbits')
    settings.msgbits = 400;
end
if ~isfield(settings, 'rotaterange')
    settings.rotaterange = 30;
end
if ~isfield(settings, 'maskimg')
    if ~isfield(settings, 'dotsize')
        settings.dotsize = 1;
    end
    % calculate mask
    settings.maskimg = zeros(settings.blocksize, settings.blocksize);
    center = (settings.blocksize+1) / 2;
    for i = 1:settings.blocksize
        for j = 1:settings.blocksize
            if (i-center)^2+(j-center)^2 <= settings.dotsize^2
                settings.maskimg(i,j) = 1;
            end
        end
    end
end
settings.mask = (settings.maskimg == 1);
summask = nnz(settings.mask);

[M,N] = size(img);
M1 = floor(M / settings.blocksize);
N1 = floor(N / settings.blocksize);
M3 = floor(M1 / settings.bigblocknumy);
N3 = floor(N1 / settings.bigblocknumx);
M2 = M3 * settings.blocksize;
N2 = N3 * settings.blocksize;

img1 = double(img);
img1(img1 == 0)= -1;
mask = double(settings.mask);
mask(mask == 0)= -1;
filterimg = imfilter(img1, -mask);
peakangle = 0;
peakval = 0;
for degree=-settings.rotaterange:settings.rotaterange
    peak = calcPeak(filterimg, degree, M3);
    if (peak > peakval)
        peakangle = degree;
        peakval = peak;
    end
    fprintf('%d -> %d\n', degree, peak);
end
disp(peakangle);
img = imrotate(img, peakangle, 'nearest', 'crop');

[blocks, count] = countAvailBlock(img, settings.blocksize, settings.samecolor, settings.skipwhite);

stream = RandStream('mt19937ar', 'Seed', settings.seed);
areaperm = stream.randperm(M3 * N3);

yperm = floor((areaperm - 1) / N3); % 0..M3-1
xperm = mod(areaperm - 1, N3); % 0..N3-1
text = zeros(1, M3 * N3);
img = round(img/255);
col = xperm * settings.blocksize;
row = yperm * settings.blocksize;
for i1 = 1:settings.bigblocknumy
    for j1 = 1:settings.bigblocknumx
        area = img((i1-1)*M2+1:i1*M2, (j1-1)*N2+1:j1*N2);
        areablocks = blocks( (i1-1)*M3+1:i1*M3, (j1-1)*N3+1:j1*N3 );
        
        count = 1;
        for k = 1:M3*N3
            if (count > numel(xperm))
                break;
            end
            if (~areablocks(yperm(k)+1, xperm(k)+1))
                continue; %skip to next bigblock
            end
            subimg = area(row(k)+1:row(k)+settings.blocksize,col(k)+1:col(k)+settings.blocksize);
            text(count) = round(nnz(subimg(settings.mask))/summask);
            count = count + 1;
        end
        text = text(1, 1:count-1);
    end
end
encodebits = text;
encodellrs = generate_llrs(encodebits, settings.mutualinfo);
[decodebits, trag] = ra_n_decoder(encodellrs, settings.q, settings.msgbits, settings.seed, settings.maxiteration);
text = binaryToArray(decodebits, settings.msgbits);
end

function [blocks,count] = countAvailBlock(img, blocksize, threshold, mode)
[M,N] = size(img);
M = floor(M / blocksize);
N = floor(N / blocksize);
blocks = ones(M, N);
for i = 1:M
    for j = 1:N
        v = img((i-1)*blocksize+1:i*blocksize, (j-1)*blocksize+1:j*blocksize);
        blocks(i,j) = checkBlock(v, threshold, mode);
    end
end
count = nnz(blocks);
end

function v = checkBlock(blockimg, threshold, mode)
m = min(blockimg(:));
v = 0;
if mode == 0
    v = 1;
elseif mode == 1
    v = (255 - m > threshold);
elseif mode == 2
    v = all(v - m > threshold);
end
end

function peak = calcPeak(img, degree, dim)
img = imrotate(img, degree, 'nearest', 'crop');
s = sum(img)/255;
s = sort(s, 1, 'descend');
peak = sum(s(1:dim));
end
